#include "main.h"

struct T {
	JSScript *script;
	JSObject *scriptObj;
};



int check_exception(JSContext *cx) {
	jsval rval;
	if (!JS_IsExceptionPending(cx)) return FALSE;		
	JS_BeginRequest(cx);
		if (JS_GetPendingException(cx, &rval))
			JS_ReportPendingException(cx);
		JS_ClearPendingException(cx);
	JS_EndRequest(cx);
	return TRUE;
}



static void evalproc(void *arg) {
	struct T *x = (struct T *)arg;
	JSContext *cx = create_context(NULL);
	jsval rval;
	if (JS_ExecuteScript(cx, JS_GetGlobalObject(cx), x->script, &rval))
		JS_MaybeGC(cx);
//#if JS_VERSION > 180
	JS_RemoveObjectRoot(cx, &x->scriptObj);
//#else
//	JS_RemoveRoot(cx, &x->scriptObj);
//#endif
	check_exception(cx);
	destroy_context(cx);
	free(x);
}



/**
 *
 */
int eval(JSContext *cx, char *code, const char *filename, int lineno, int async, jsval *rval) {
	trace1("eval");
	struct T *x = (struct T *)calloc(sizeof(struct T), 1);
	int ret = FALSE;

	trace3("%s, async: %d", filename, async);

	if (!filename)
		filename = "<eval>";		

	if (!lineno)
		lineno = 1;

	*rval = JSVAL_VOID;
	
	JS_BeginRequest(cx);
		x->script = JS_CompileScript(cx, JS_GetGlobalObject(cx), code, strlen(code), filename, lineno);

		if (x->script)
			x->scriptObj = JS_NewScriptObject(cx, x->script);

		if (x->scriptObj)
			if (JS_ExecuteScript(cx, JS_GetGlobalObject(cx), x->script, rval))
				ret = TRUE;

		JS_MaybeGC(cx);
	JS_EndRequest(cx);

	if (x) free(x);
	return ret;
}



/**
 *
 */
int eval_stream(JSContext *cx, FILE *f, const char *name, int async, jsval *rval) {
	trace1("eval_stream");
	trace5("name: %s, async: %d", name, async);
	
	int len, lineno=1;
	char *buf, *b;
	
	if ( ! (b = buf = (char *)malloc(EVAL_STREAM_BUF_SIZE) ) )
		fatal("malloc()");
	
	*buf = 0;
	
	js_preprocess(buf, EVAL_STREAM_BUF_SIZE, f);
	//printf("***BUF:***\n%s", buf); exit(1);

	int ret = eval(cx, b, name, lineno, async, rval);

	return ret;
}




/**
 *
 */
int eval_file(JSContext *cx, char *filename, int async, jsval *rval) {
	FILE *f;
	trace1("eval_file");
	trace5("filename: %s, async: %d", filename, async);

	if ( !filename || (strcmp(filename, "-") == 0) || (strcmp(filename, "") == 0) )
		return eval_stream(cx, stdin, "<stdin>", async, rval);
		
	f = fopen(filename, "r");
		
	if (!f)
		return eval(cx, filename, "<inline>", 1, async, rval);
	
	char *bn = basename(filename);
	int ret = eval_stream(cx, f, bn, async, rval);
	free(bn);
	
	fclose(f);
	return ret;
}



